package sk.ogame.realm.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import sk.ogame.brain.Memory;
import sk.ogame.entity.Building;
import sk.ogame.entity.Fleet;
import sk.ogame.entity.Planet;
import sk.ogame.entity.PlanetOverview;
import sk.ogame.realm.exception.CommunicationException;
import sk.ogame.realm.utils.TimeUtil;

import java.util.List;
import java.util.Objects;

/**
 * @author 支绍昆
 * 2023/2/14
 * Http客户端服务 用于模拟浏览器访问服务器
 **/
@Service
public class ClientHttpService {

    @Autowired
    private RestTemplate restTemplate;
    @Autowired
    private Memory memory;

    //星球概况列表
    public List<PlanetOverview> planetOverviewList() {
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("mod", "planetlist");
        params.add("xid", "-3");
        String body = send(params);
        List<PlanetOverview> list = parseOverview(body);
        memory.putPlanetOverview(list);
        return list;
    }

    //切换当前星球获取信息
    public Planet planetChangeById(int planetId) {
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("mod", "planet");
        params.add("change_pid", "" + planetId);
        params.add("xid", "-2");
        String body = send(params);
        Planet planet = parsePlanet(body);
        planet.setUsertime(TimeUtil.now());
        memory.putPlanet(planet);
        return planet;
    }

    //刷新当前星球信息
    public Planet planetRefresh() {
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("mod", "planet");
        params.add("xid", "0");
        String body = send(params);
        Planet planet = parsePlanet(body);
        planet.setUsertime(TimeUtil.now());
        memory.putPlanet(planet);
        return planet;
    }

    //升级当前星球建筑
    public Planet planetBuildUp(int buildId) {
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("mod", "planet");
        params.add("build_id", "" + buildId);
        params.add("build_count", "1");
        params.add("xid", "2");
        String body = send(params);
        return parsePlanet(body);
    }

    //当前星球建筑详情
    public List<Building> planetBuildDetail() {
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("mod", "building");
        params.add("type", "1");
        params.add("xid", "1");
        String body = send(params);
        return parseBuilding(body);
    }

    //舰队任务
    public void fleetMission(Fleet fleet) {
        MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
        params.add("mod", "fleet");
        params.add("xid", "2");
        params.add("mission", String.valueOf(fleet.getMission()));
        params.add("target_galaxy", String.valueOf(fleet.getTarget_galaxy()));
        params.add("target_system", String.valueOf(fleet.getTarget_system()));
        params.add("target_planet", String.valueOf(fleet.getTarget_planet()));
        params.add("target_type", String.valueOf(fleet.getTarget_type()));
        params.add("fleets", String.valueOf(fleet.getFleets()));
        params.add("speed", String.valueOf(fleet.getSpeed()));
        params.add("stay_time", String.valueOf(fleet.getStay_time()));
        params.add("fleet_metal", String.valueOf(fleet.getMetal()));
        params.add("fleet_crystal", String.valueOf(fleet.getCrystal()));
        params.add("fleet_deuterium", String.valueOf(fleet.getDeuterium()));
        params.add("attack_code", String.valueOf(fleet.getAttack_code()));
        params.add("fleet_hash", fleet.getHash());
        String body = send(params);
        Planet planet = parsePlanet(body);
        planet.setUsertime(TimeUtil.now());
        memory.putPlanet(planet);
    }

    //------------------------------------------- private -------------------------------------------------

    private String send(MultiValueMap<String, String> params) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(params, headers);
        ResponseEntity<String> response = restTemplate.postForEntity("http://s9.ogame.jsets.com/server.php", httpEntity, String.class);
        isOk(response);
        return response.getBody();
    }

    private static void isOk(ResponseEntity<String> response) {
        if (response.getStatusCodeValue() != 200) {
            throw new CommunicationException("communication error : " + JSON.toJSONString(response), CommunicationException.CONTENT_ERROR);
        }
        if (Objects.isNull(response.getBody()) || response.getBody().startsWith("[{\"error\"")) {
            throw new CommunicationException("communication error : " + JSON.toJSONString(response), CommunicationException.CONTENT_ERROR);
        }
    }

    private Planet parsePlanet(String body) {
        JSONArray jsonArray = JSON.parseArray(body);
        if (Objects.isNull(jsonArray)) {
            return null;
        }
        for (Object o : jsonArray) {
            JSONObject jsonObject = (JSONObject) o;
            if (jsonObject.getString("mod").equals("planet")) {
                return jsonObject.getJSONObject("msg").getObject("planet", Planet.class);
            }
        }
        return null;
    }

    private List<Building> parseBuilding(String body) {
        JSONArray jsonArray = JSON.parseArray(body);
        if (Objects.isNull(jsonArray)) {
            return null;
        }
        for (Object o : jsonArray) {
            JSONObject jsonObject = (JSONObject) o;
            if (jsonObject.getString("mod").equals("building")) {
                return jsonObject.getObject("msg", new TypeReference<List<Building>>() {
                });
            }
        }
        return null;
    }

    private List<PlanetOverview> parseOverview(String body) {
        JSONArray jsonArray = JSON.parseArray(body);
        if (Objects.isNull(jsonArray)) {
            return null;
        }
        for (Object o : jsonArray) {
            JSONObject jsonObject = (JSONObject) o;
            if (jsonObject.getString("mod").equals("planetlist")) {
                return jsonObject.getJSONObject("msg").getObject("list", new TypeReference<List<PlanetOverview>>() {
                });
            }
        }
        return null;
    }

}
